/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.com.tbp.persitence.dao.impl;

import br.com.tbp.exception.PersistenciaException;
import br.com.tbp.model.domain.Consultor;
import br.com.tbp.model.domain.Usuario;
import br.com.tbp.model.domain.constant.CategoriaDeUsuario;
import br.com.tbp.persitence.GerenciadorDeConexao;
import br.com.tbp.persitence.GerenciadorDeQuery;
import br.com.tbp.persitence.dao.UsuarioDao;
import br.com.tbp.utils.DateUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author Diego Freire
 */
public class UsuarioDaoImpl implements UsuarioDao {

    private Connection conn = null;
    private PreparedStatement pr = null;
    private ResultSet rs = null;

    public void adicionar(Usuario usuario) throws PersistenciaException {
        if (usuario == null) {
            throw new PersistenciaException("Não foi informado o usuário a cadastrar.");
        }

        try {
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement(GerenciadorDeQuery.getQuery("usuario.insert"),
                    Statement.RETURN_GENERATED_KEYS);
            pr.setString(1, usuario.getNome());
            pr.setString(2, usuario.getLogin());
            pr.setString(3, usuario.getSenha());
            pr.setString(4, usuario.getEmail());
            pr.setDate(5, DateUtils.dataObjetoParaDataBancoDeDados(usuario.getDt_cadastro()));
            pr.setBoolean(6, usuario.isAtivo());
            pr.setString(7, usuario.getCategoria().name());
            pr.setTimestamp(8, usuario.getUltimoAcesso());
            pr.setLong(9, usuario.getConsultor() != null ? usuario.getConsultor().getId() : 0);
            pr.executeUpdate();

            rs = pr.getGeneratedKeys();
            if (rs.first()) {
                long id = rs.getLong(1);
                usuario.setUsuarioId(id);
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível cadastrar o usuário.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }
    }

    public int modificar(Usuario usuario) throws PersistenciaException {
        if (usuario == null) {
            throw new PersistenciaException("Não foi informado o usuário a modificar.");
        }
        int modificou = 0;
        try {
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement(GerenciadorDeQuery.getQuery("usuario.update"));
            pr.setString(1, usuario.getNome());
            pr.setString(2, usuario.getLogin());
            pr.setString(3, usuario.getEmail());
            pr.setBoolean(4, usuario.isAtivo());
            pr.setString(5, usuario.getCategoria().name());
            pr.setLong(6, usuario.getConsultor() != null ? usuario.getConsultor().getId() : 0);
            pr.setLong(7, usuario.getUsuarioId());

            modificou = pr.executeUpdate();

        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível modificar o usuário.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr);
        }
        return modificou;
    }

    public int modificarSenha(long usuarioId, String antiga, String nova) throws PersistenciaException {
        int linhasAlteradas = 0;

        try {
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement(GerenciadorDeQuery.getQuery("usuario.get.senha"));
            pr.setLong(1, usuarioId);
            rs = pr.executeQuery();
            if (rs.first()) {
                String senhaCorreta = rs.getString("SENHA");
                if (senhaCorreta.equals(antiga)) {
                    pr = conn.prepareStatement(GerenciadorDeQuery.getQuery("usuario.update.senha"));
                    pr.setString(1, nova);
                    pr.setLong(2, usuarioId);
                    linhasAlteradas = pr.executeUpdate();
                }
            }

        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível modificar a senha do usuário.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }

        return linhasAlteradas;
    }

    public int modificarSenha(long usuarioId, String nova) throws PersistenciaException {
        int linhasAlteradas = 0;
        try {
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement(GerenciadorDeQuery.getQuery("usuario.update.senha"));
            pr.setString(1, nova);
            pr.setLong(2, usuarioId);
            linhasAlteradas = pr.executeUpdate();
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível modificar a senha do usuário.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }
        return linhasAlteradas;
    }

    public long maxUsuarioId() throws PersistenciaException {
        long usuarioId = 0;

        try {
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement(GerenciadorDeQuery.getQuery("usuario.maxId"));
            rs = pr.executeQuery();
            if (rs.first()) {
                usuarioId = rs.getLong("usuarioId");
                usuarioId++;
            }

        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível recuperar o último usuárioId.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }

        return usuarioId;
    }

    public Usuario get(long usuarioId) throws PersistenciaException {
        Usuario usuario = null;

        try {
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement(GerenciadorDeQuery.getQuery("usuario.get"));
            pr.setLong(1, usuarioId);
            rs = pr.executeQuery();
            if (rs.first()) {
                usuario = this.criarUsuario(rs);
            }

        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível buscar o usuário.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }

        return usuario;
    }

    public Usuario login(String login, String senha) throws PersistenciaException {
        Usuario usuario = null;

        try {
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement(GerenciadorDeQuery.getQuery("usuario.logar"));
            pr.setString(1, login);
            rs = pr.executeQuery();
            if (rs.first()) {
                String senhaCorreta = rs.getString("SENHA");
                if (senhaCorreta.equals(senha)) {
                    usuario = this.get(rs.getLong("ID"));
                    if (usuario != null) {
                        if (conn.isClosed()) {
                            conn = GerenciadorDeConexao.abreConexao();
                        }
                        pr = conn.prepareStatement(GerenciadorDeQuery.getQuery("usuario.update.ultimo.acesso"));
                        pr.setLong(1, usuario.getUsuarioId());
                        pr.executeUpdate();
                    }
                }
            }

        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível realizar o login do usuário.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }

        return usuario;
    }

    public List<Usuario> listar() throws PersistenciaException {
        List<Usuario> lista = new ArrayList<Usuario>();

        try {

            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement(GerenciadorDeQuery.getQuery("usuario.listar"));
            rs = pr.executeQuery();
            while (rs.next()) {
                Usuario usuario = this.criarUsuario(rs);
                lista.add(usuario);
            }

        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível listar os usuários.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }

        return lista;
    }

    /**
     * Método auxiliar para criar usuários a partir de um resultset
     * @param rs
     * @return o usuário criado
     */
    private Usuario criarUsuario(ResultSet rs) throws PersistenciaException {
        Usuario usuario = null;
        try {
            usuario = new Usuario();
            usuario.setUsuarioId(rs.getLong("id"));
            usuario.setNome(rs.getString("nome"));
            usuario.setLogin(rs.getString("login"));
            usuario.setSenha(rs.getString("senha"));
            usuario.setEmail(rs.getString("email"));
            usuario.setDt_cadastro(DateUtils.dataBancoDeDadosParaDataObjeto(rs.getDate("dt_cadastro")));
            usuario.setAtivo(rs.getBoolean("ativo"));
            usuario.setCategoria(CategoriaDeUsuario.valueOf(rs.getString("categoria")));
            usuario.setUltimoAcesso(rs.getTimestamp("ultimo_acesso"));
            long consultorId = rs.getLong("id_consultor");
            if (consultorId > 0) {
                usuario.setConsultor(new Consultor(consultorId));
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível obter os dados do usuário.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        }
        return usuario;
    }

    public List<Usuario> pesquisarPeloNome(String nome) throws PersistenciaException {
        List<Usuario> lista = new ArrayList<Usuario>();

        try {

            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement(GerenciadorDeQuery.getQuery("usuario.select.nome"));
            pr.setString(1, "%" + nome + "%");
            rs = pr.executeQuery();
            while (rs.next()) {
                Usuario usuario = this.criarUsuario(rs);
                lista.add(usuario);
            }

        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível pesquisar os usuários pelo nome.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }

        return lista;
    }

    public List<Usuario> pesquisarPeloLogin(String login) throws PersistenciaException {
        List<Usuario> lista = new ArrayList<Usuario>();

        try {

            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement(GerenciadorDeQuery.getQuery("usuario.select.login"));
            pr.setString(1, "%" + login + "%");
            rs = pr.executeQuery();
            while (rs.next()) {
                Usuario usuario = this.criarUsuario(rs);
                lista.add(usuario);
            }

        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível pesquisar os usuários pelo login.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }

        return lista;
    }
}
